/*
 * GMatchday.java
 * Created on 30 juin 2007
 *
 * Glacéo Internet Platform
 * http://sourceforge.net/projects/chm/
 *
 * Copyright (c) 2005-2007, Jan Janke (VirtualHockey Project)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hockeo.vhbase.data.dao.season;


import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;

import org.hibernate.annotations.Where;

import com.hockeo.vhbase.data.dao.IGEntity;
import com.hockeo.vhbase.data.dao.contest.GContestElement;
import com.hockeo.vhbase.data.dao.match.GMatch;
import com.hockeo.vhbase.data.dao.standings.GStandings;
import com.hockeo.vhbase.data.helper.GStandingsType;

/**
 * Container for all matches that take place for a particular contest element at the same
 * day. One club can only have one match per matchday.
 *
 * @version $Id$
 * @author jjanke
 */
@Entity
@Table( name = "s_matchday" )
public class GMatchday implements IGEntity, Comparable<GMatchday>
{
  @Id
  @Column( name = "id" )
  @GeneratedValue( strategy = GenerationType.AUTO )
  private int              d_nId;

  /**
   * Contest element specific matchday number.
   */
  @Column( name = "num" )
  private int              d_nNum;

  /**
   * Indicates if this matchday is the first of a contest element.
   */
  @Column( name = "first" )
  private boolean          d_fIsFirst;

  /**
   * Indicates if this matchday is the last of a contest element.
   */
  @Column( name = "last" )
  private boolean          d_fIsLast;

  @ManyToOne( fetch = FetchType.LAZY )
  @JoinColumn( name = "contest_element_id" )
  private GContestElement  d_contestElement;

  @ManyToOne( fetch = FetchType.LAZY )
  @JoinColumn( name = "moveday_id" )
  private GMoveday         d_moveday;

  @Column( name = "analysed" )
  private boolean          d_fAnalysed = false;

  @OneToMany( mappedBy = "d_matchday", cascade = { CascadeType.REMOVE } )
  @OrderBy( "d_nId" )
  private List<GMatch>     d_listMatches;

  @OneToMany( mappedBy = "d_matchday", cascade = { CascadeType.REMOVE } )
  @Where( clause = "type = 'TOTAL'" )
  @OrderBy( "d_nRank" )
  private List<GStandings> d_listStandingsTotal;

  @OneToMany( mappedBy = "d_matchday", cascade = { CascadeType.REMOVE } )
  @Where( clause = "type = 'HOME'" )
  @OrderBy( "d_nRank" )
  private List<GStandings> d_listStandingsHome;

  @OneToMany( mappedBy = "d_matchday", cascade = { CascadeType.REMOVE } )
  @Where( clause = "type = 'AWAY'" )
  @OrderBy( "d_nRank" )
  private List<GStandings> d_listStandingsAway;

  /** Default parameterless constructor. */
  protected GMatchday()
  {}

  /**
   * Creates a new GMatchday object.
   *
   * @param contestElement the contest element for which to create the matchday
   * @param nNum the matchday number (in each contest element the matchdays are numbered
   *          from 1 to N)
   * @param fIsFirst indicates whether this is the first matchday of the contest element
   * @param fIsLast indicates whether this is the last matchday of the contest element
   */
  public GMatchday( GContestElement contestElement, int nNum, boolean fIsFirst, boolean fIsLast )
  {
    d_contestElement = contestElement;
    d_nNum = nNum;
    d_fIsFirst = fIsFirst;
    d_fIsLast = fIsLast;
  }

  public List<GMatch> getMatches()
  {
    return d_listMatches;
  }

  public boolean isAnalysed()
  {
    return d_fAnalysed;
  }

  /**
   * Sets the matchday's analysed flag.
   *
   * @param flag <code>true</code> indicates that the matchday has been analysed (i.e. all
   *          matches have been evaluated and standings created etc.)
   */
  public void setAnalysed( boolean flag )
  {
    d_fAnalysed = flag;
  }

  /**
   * Returns all standings associated to this matchday. Only matchdays belonging to round
   * robin contest elements can have associated standings (if they have been played).
   *
   * @param the type of standings to be retrieved
   */
  public List<GStandings> getStandings( GStandingsType type )
  {
    switch ( type )
    {
      case TOTAL:
        return d_listStandingsTotal;

      case HOME:
        return d_listStandingsHome;

      case AWAY:
        return d_listStandingsAway;

      default:
        throw new IllegalArgumentException( "The standings type " + type.name() + " is not supported." );
    }
  }

  public int getNum()
  {
    return d_nNum;
  }

  /**
   * Indicates whether this matchday is the first of the contest element it belongs to.
   */
  public boolean isFirst()
  {
    return d_fIsFirst;
  }

  /**
   * Indicates whether this matchday is the last of the contest element it belongs to.
   */
  public boolean isLast()
  {
    return d_fIsLast;
  }

  public GContestElement getContestElement()
  {
    return d_contestElement;
  }

  public GMoveday getMoveday()
  {
    return d_moveday;
  }

  /**
   * Sets the moveday this matchday is attached to. This method is intentionally only
   * package visible as it is not supposed to be called from other classes than GMoveday.
   *
   * @param moveday the moveday this matchday is attached to
   */
  void setMoveday( GMoveday moveday )
  {
    d_moveday = moveday;
  }

  public int getId()
  {
    return d_nId;
  }

  public Class<? extends IGEntity> getGEntityClass()
  {
    return GMatchday.class;
  }

  public boolean instanceOf( Class<? extends IGEntity> classOther )
  {
    return classOther.isAssignableFrom( getGEntityClass() );
  }

  /*
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals( Object obj )
  {
    try
    {
      return d_nId == ( (GMatchday) obj ).getId();
    }
    catch ( Exception ex ) // especially ClassCastException(s) may happen
    {
      return false;
    }
  }

  /*
   * @see java.lang.Object#hashCode()
   */
  @Override
  public int hashCode()
  {
    return d_nId;
  }

  /*
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString()
  {
    return String.valueOf( d_nId ) + " (contest element: " + d_contestElement.getId() + " / " + d_nNum + ")";
  }

  /**
   * Orders the matchday by moveday, contest element and matchday number.
   */
  public int compareTo( GMatchday other )
  {
    int nTmp = this.getMoveday().compareTo( other.getMoveday() );
    if ( nTmp != 0 )
      return nTmp;

    nTmp = this.getContestElement().compareTo( other.getContestElement() );
    if ( nTmp != 0 )
      return nTmp;

    return this.getNum() - other.getNum();
  }
}
